"""
通用方法类
__init__()：启动浏览器
login()：登录操作
add_devicemodel：添加设备型号
get_first_page_device_models：获得第一个设备型号信息
del_first_item：删除第一个设备型号信息
"""
from selenium.common import NoSuchElementException, TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from config import *
import time

class SMP_COMMON:
    wd=None  # 类属性保存浏览器实例

    @classmethod
    def setUp(cls):
        if cls.wd is None:
            # 浏览器配置对象
            options = webdriver.ChromeOptions()
            options.add_argument("--no-sandbox")  # 解决沙盒权限问题
            options.add_argument("--disable-dev-shm-usage")  # 解决共享内存问题
            options.add_argument("--start-maximized")  # 最大化窗口
            # 禁用控制台日志
            options.add_experimental_option(
                "excludeSwitches", ["enable-logging"])
            # 获取chromedriver
            chromedriver_path = r"F:\浏览器\Google Chrome\chromedriver-win64\chromedriver.exe"
            service = Service(executable_path=chromedriver_path)

            # 启动浏览器驱动
            cls.wd = webdriver.Chrome(service=service, options=options)
            cls.wd.implicitly_wait(10)  # 设置隐式等待

    @classmethod
    def tearDown(cls):
        """关闭浏览器"""
        if cls.wd is not None:
            print("正在关闭浏览器")
            cls.wd.quit()
            cls.wd = None

    # 登录
    def login(self,username,password):
        self.setUp()
        self.wd.get(SMP_URL_LOGIN)
        time.sleep(2)

        if username is not None:
            self.wd.find_element(By.ID, 'username').send_keys(username)
        if password is not None:
            self.wd.find_element(By.ID, 'password').send_keys(password)
        time.sleep(2)

        self.wd.find_element(By.ID, 'loginBtn').click()


    """
    设备型号
    """
    # 添加设备型号
    def add_devicemodel(self,devType,name,desc):
        self.setUp()
        # 创建Select对象
        select = Select(commonSmp.wd.find_element(By.ID, 'device-type'))
        # 通过Select对象选中目标
        select.select_by_visible_text(devType)
        ele = commonSmp.wd.find_element(By.ID, 'device-model')
        ele.clear()  # 清除可能残留的信息
        ele.send_keys(name)

        ele = commonSmp.wd.find_element(By.ID, 'device-model-desc')
        ele.clear()  # 清除可能残留的信息
        ele.send_keys(desc)

        commonSmp.wd.find_element(By.CSS_SELECTOR, '.add-one-submit-btn-div .btn').click()

    # 获取设备型号列表的第一列
    def get_first_page_device_models(self):
        self.setUp()
        time.sleep(2)

        self.wd.implicitly_wait(0)  # 临时禁用隐式等待
        values=self.wd.find_elements(By.CSS_SELECTOR, '.field-value')
        self.wd.implicitly_wait(10)

        deviceModels=[]
        for idx,value in enumerate(values):
            if (idx+1) % 3==0:  # 每遇到第3的倍数个元素
                deviceModels.append(  # 取前两个元素和当前元素组成一组
                    [values[idx-2].text,values[idx-1].text,values[idx].text]
                )
        return deviceModels


    """
    业务规则
    """
    # 添加业务规则
    def add_service_rule(self,ruleName:str,ruleType:str,
                         minFee:str,estFee:str,feeRate=None,desc:str=None):
        """
        :param ruleName:规则名称
        :param ruleType:规则类型，只能是:后付费-上报业务量、预付费-下发费用、预付费-下发业务量
        :param minFee:最小费用，不需要时，填写空字符串
        :param estFee:预计费用，不需要时，填写空字符串
        :param desc:描述
        :param feeRate:费率，如果ruleType是
            预付费-下发费用: 不用填写
            预付费-下发业务量: 格式为 ['千瓦时','1'], 元素分别是 单位、单价
            后付费-上报业务量: 格式为[
                ['10L','小时','1'],
                ['20L','小时','2']
            ], 每个元素里面分别是: 业务码、单位、单价
        :return:
        """

        ele=self.wd.find_element(By.CSS_SELECTOR,'.add-one-form > .field:nth-child(1) > input')
        ele.clear()
        ele.send_keys(ruleName)

        select=Select(self.wd.find_element(By.CSS_SELECTOR,'.add-one-form select'))
        select.select_by_visible_text(ruleType)
        time.sleep(1)

        if ruleType !='后付费-上报业务量':
            ele=self.wd.find_element(By.CSS_SELECTOR,'.add-one-form > .field:nth-child(3) > input')
            ele.clear()
            if minFee:
                ele.send_keys(minFee)

            ele =self.wd.find_element(By.CSS_SELECTOR,'.add-one-form > .field:nth-child(4) > input')
            ele.clear()
            if estFee:
                ele.send_keys(estFee)

        if desc:
            ele=self.wd.find_element(
                By.XPATH,
                "//*[@class='add-one-submit-btn-div']/preceding-sibling::*[1]/input"
            )
            ele.clear()
            ele.send_keys(desc)

        if ruleType =='预付费-下发费用':
            pass  # 没有费率设置

        elif ruleType =='后付费-上报业务量':
            self.wd.implicitly_wait(0)
            while True:
                el=self.wd.find_elements(By.CSS_SELECTOR,'.fee-rate span:last-child')
                if el:
                    el[0].click()
                    time.sleep(0.5)
                else:
                    break
            self.wd.implicitly_wait(10)
            for one in feeRate:
                self.wd.find_element(By.CSS_SELECTOR,'.fee-rate-list button').click()
                entry=self.wd.find_element(By.CSS_SELECTOR,'div.fee-rate:nth-last-child(2)')
                # 业务码
                entry.find_element(By.CSS_SELECTOR,'input:nth-of-type(1)').send_keys(one[0])
                # 计费单位
                entry.find_element(By.CSS_SELECTOR, 'input:nth-of-type(2)').send_keys(one[1])
                # 单位价格
                entry.find_element(By.CSS_SELECTOR, 'input:nth-of-type(3)').send_keys(one[2])

        elif ruleType =='预付费-下发业务量':
            entry=self.wd.find_element(By.CSS_SELECTOR,'div.fee-rate')

            # 计费单位
            entry.find_element(By.CSS_SELECTOR, 'input:nth-of-type(1)').send_keys(feeRate[0])
            # 单位价格
            entry.find_element(By.CSS_SELECTOR, 'input:nth-of-type(2)').send_keys(feeRate[1])

        else:
            raise Exception('ruleType 参数值错误')

        self.wd.find_element(By.CSS_SELECTOR,'.add-one-submit-btn-div .btn').click()
        time.sleep(1)

    def get_first_page_service_rules(self):
        # 确保元素加载完成
        WebDriverWait(self.wd, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, ".result-list-item-info"))
        )

        self.wd.implicitly_wait(0)
        items = self.wd.find_elements(By.CSS_SELECTOR, '.result-list-item-info')
        self.wd.implicitly_wait(10)

        rules = []
        for item in items:
            try:
                # 规则名称
                name_ele = item.find_element(
                    By.CSS_SELECTOR,
                    '.field:nth-child(1) .field-value'
                )
                name = name_ele.text.strip()

                # 即使名称为空也处理
                # 系统可能允许空名称的规则

                # 规则类型
                rule_type_ele = item.find_element(
                    By.CSS_SELECTOR,
                    '.field:nth-child(2) .field-value'
                )
                rule_type = rule_type_ele.text.strip()

                # 规则内容区域
                content_ele = item.find_element(
                    By.CSS_SELECTOR,
                    '.field:nth-child(3) .field-value'
                )

                content = {}

                # 根据规则类型采用不同解析策略
                if rule_type == "预付费-下发业务量":
                    # 最小消费
                    min_consume_ele = content_ele.find_element(
                        By.XPATH,
                        './/div[contains(., "最小消费")]'
                    )
                    min_consume = min_consume_ele.find_element(
                        By.CSS_SELECTOR,
                        '.field-value'
                    ).text.strip()
                    content["最小消费"] = min_consume

                    # 预估消费
                    est_consume_ele = content_ele.find_element(
                        By.XPATH,
                        './/div[contains(., "预估消费")]'
                    )
                    est_consume = est_consume_ele.find_element(
                        By.CSS_SELECTOR,
                        '.field-value'
                    ).text.strip()
                    content["预估消费"] = est_consume

                    # 费率
                    try:
                        fee_ele = content_ele.find_element(
                            By.XPATH,
                            './/div[contains(., "费率")]'
                        )
                        fee_items = fee_ele.find_elements(
                            By.CSS_SELECTOR,
                            '.sub-field-value'
                        )
                        if fee_items:
                            fee_details = [item.text.strip() for item in fee_items]
                            content["费率"] = " ".join(fee_details)
                        else:
                            content["费率"] = "无费率信息"
                    except NoSuchElementException:
                        content["费率"] = "无费率信息"

                elif rule_type == "预付费-下发费用":
                    # 最小消费
                    min_consume_ele = content_ele.find_element(
                        By.XPATH,
                        './/div[contains(., "最小消费")]'
                    )
                    min_consume = min_consume_ele.find_element(
                        By.CSS_SELECTOR,
                        '.field-value'
                    ).text.strip()
                    content["最小消费"] = min_consume

                    # 预估消费
                    est_consume_ele = content_ele.find_element(
                        By.XPATH,
                        './/div[contains(., "预估消费")]'
                    )
                    est_consume = est_consume_ele.find_element(
                        By.CSS_SELECTOR,
                        '.field-value'
                    ).text.strip()
                    content["预估消费"] = est_consume

                elif rule_type == "后付费-上报业务量":
                    # 费率
                    try:
                        fee_ele = content_ele.find_element(
                            By.XPATH,
                            './/div[contains(., "费率")]'
                        )
                        fee_entries = fee_ele.find_elements(
                            By.CSS_SELECTOR,
                            'div[style*="display: grid"]'
                        )
                        fee_details = []
                        for entry in fee_entries:
                            fee_items = entry.find_elements(
                                By.CSS_SELECTOR,
                                '.sub-field-value'
                            )
                            fee_details.append(" ".join([item.text.strip() for item in fee_items]))
                        content["费率"] = " | ".join(fee_details)
                    except NoSuchElementException:
                        # 没有费率区域，保持默认的空字符串
                        pass
                    except Exception as e:
                        print(f"解析后付费规则费率时出错: {str(e)}")

                # 规则描述
                try:
                    desc_ele = item.find_element(
                        By.CSS_SELECTOR,
                        '.field:nth-child(4) .field-value'
                    )
                    desc_text = desc_ele.text.strip()
                except:
                    desc_text = ""

                rules.append([name, rule_type, content, desc_text])

            except Exception as e:
                print(f"提取规则时出错: {str(e)}")
                continue

        return rules


    """
    设备
    """
    # 添加设备
    def add_device(self, devType, name, ruleName, devNumber, desc):
        # 设备类型选择
        dev_type_select = Select(self.wd.find_element(By.ID, 'device-type'))
        dev_type_select.select_by_visible_text(devType)

        # 设备型号选择
        dev_model_select = Select(self.wd.find_element(By.ID, 'device-model'))
        dev_model_select.select_by_visible_text(name)

        # 业务规则选择
        rule_select = Select(self.wd.find_element(By.ID, 'svc-rule-id'))
        rule_select.select_by_visible_text(ruleName)

        try:
            # 尝试使用 ID 定位设备编号
            dev_number_input = self.wd.find_element(By.ID, 'device-number')
        except:
            # 如果 ID 不存在，使用 XPath 定位
            dev_number_label = self.wd.find_element(By.XPATH, '//span[text()="设备编号"]')
            dev_number_input = dev_number_label.find_element(By.XPATH, './following-sibling::input')

        dev_number_input.clear()
        dev_number_input.send_keys(devNumber)

        try:
            # 尝试使用 ID 定位设备描述
            dev_desc_input = self.wd.find_element(By.ID, 'device-desc')
        except:
            # 如果 ID 不存在，使用 XPath 定位
            dev_desc_label = self.wd.find_element(By.XPATH, '//span[text()="设备描述"]')
            dev_desc_input = dev_desc_label.find_element(By.XPATH, './following-sibling::input')

        dev_desc_input.clear()
        dev_desc_input.send_keys(desc)

        # 点击确定按钮
        self.wd.find_element(By.CSS_SELECTOR, '.add-one-submit-btn-div .btn').click()

    # 获得第一列数据
    def get_first_page_device(self):
        # 确保元素加载完成
        try:
            WebDriverWait(self.wd, 10).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, ".result-list-item"))
            )
        except TimeoutException:
            return []  # 没有设备项

        self.wd.implicitly_wait(0)
        try:
            items = self.wd.find_elements(By.CSS_SELECTOR, '.result-list-item')
        except:
            items = []
        self.wd.implicitly_wait(10)

        devices = []
        for item in items:
            try:
                # 提取设备信息部分
                info_div = item.find_element(By.CSS_SELECTOR, '.result-list-item-info')

                # 获取所有字段容器
                fields = info_div.find_elements(By.CSS_SELECTOR, '.field')

                # 提取字段值
                field_values = []
                for field in fields:
                    try:
                        value_ele = field.find_element(By.CSS_SELECTOR, '.field-value')
                        field_values.append(value_ele.text.strip())
                    except:
                        field_values.append("")

                # 提取描述信息
                try:
                    desc_ele = item.find_element(
                        By.CSS_SELECTOR,
                        '.result-list-item-desc .field-value'
                    )
                    desc_text = desc_ele.text.strip()
                except:
                    desc_text = ""

                # 添加描述到字段值列表
                field_values.append(desc_text)

                # 添加到设备列表
                devices.append(field_values)

            except Exception as e:
                print(f"提取设备时出错: {str(e)}")
                continue

        return devices

    # 删除键（通用）
    def del_first_item(self):
        try:
            # 确保有规则存在
            WebDriverWait(self.wd, 5).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, ".result-list-item"))
            )

            # 找到第一条规则的删除按钮
            delBtn = self.wd.find_element(
                By.CSS_SELECTOR,
                '.result-list-item:first-child .result-list-item-btn-bar span:first-child'
            )
            delBtn.click()

            # 处理删除警告框
            try:
                WebDriverWait(self.wd, 2).until(EC.alert_is_present())
                alert = self.wd.switch_to.alert
                alert.accept()  # 点击确定删除
                time.sleep(1)  # 等待删除完成
            except TimeoutException:
                # 没有警告框出现，继续
                pass

        except (NoSuchElementException, TimeoutException):
            # 没有规则可删除
            print("没有找到可删除的规则，跳过删除操作")


# 实例化
commonSmp=SMP_COMMON()
